package com.example.demo.Controller;

/**
 *  网页账户密码登录
 *
 *  1. 用户扫码登录
 *  2. 管理员，工作者账号密码登录
 *  3. 进行数据库校验
 *      a.校验成功，jwt 生成token 保存在redis上 返回token，状态码
 *      b.校验不成功 返回状态码与错误信息
 *
 *  小程序端账号密码登录
 *  小程序端
 *  1.小程序端 页面加载时自动将openId 调用api 访问是否关联  查询是否有当前openId 的记录
 *      - 关联 可以使用微信扫码 登录
 *      - 未关联 页面展示 未关联
 *  2.小程序登录
 *      a.账号密码登录 保障本地token是最新的
 *  小程序授权
 *           1.1  前端用户点击扫码登录， 前端调用api  获取以UUID命名 的 二维码图片url （图片存储在cos中 一天后自动清理）
 *            1.2  前端使用setTimeOut 每一秒调用登录api, 查询redis key 为 UUID 的value 值是否为空 若为空 等待用户授权==》value应为主键id
 *            1.3
 * //           1.3  后端等待用户通过小程序扫码后，授权给前端，将小程序登录后存储的token再设置到二维码redis UUID key 对应的value中
 * //           1.4  登录成功 将token取出来 存放在cookie中
 *
 *  2.登录成功  可以点击账号关联
* */



//

import com.example.demo.Config.QrcodeWebsocket;
import com.example.demo.Dao.PersonRepository;
import com.example.demo.Entity.Person;
import com.example.demo.IntelligenceCommunitySystemApplication;
import com.example.demo.Service.AuthService;
import com.example.demo.Service.VerifyService;
import com.example.demo.Utils.CodeUtils;
import com.example.demo.Utils.ConstUtils;
import com.example.demo.Utils.RedisUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.naming.AuthenticationException;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Date;

/**
 * 后台登录逻辑需接入腾讯防水墙，https://007.qq.com/；
 * <p>
 * 提供API，住户可以注册账号并完成微信账号绑定
 * <p>
 * 网页注册
 * <p>
 * 网页登录
 * <p>
 * 小程序登录
 *
 * @blame Android Team
 */
@CrossOrigin
@RestController
@Slf4j
public class LoginController {
    @Resource
    private AuthService authService;
    @Resource
    private PersonRepository personRepository;
    @Resource
    private RedisUtils redisUtils;

    public static final int MAX_VALID_NUM = 3;


    @GetMapping(value = "authentication/canverify")
    public CodeUtils.Message canVerify(HttpServletRequest request){
        try {
            String ip = request.getRemoteHost();
            if (!redisUtils.hasKey(ip)){
                redisUtils.set(ip,1,10);
                return CodeUtils.Message.builder().code(20000).message("no").build();
            }
            int num = (Integer)redisUtils.get(ip);
            num+=1;
            redisUtils.fix(ip,num);
            if (num>=MAX_VALID_NUM){
                return CodeUtils.Message.builder().code(20000).message("yes").build();
            }
            return CodeUtils.Message.builder().code(20000).message("no").build();
        }catch (Exception e){
            e.printStackTrace();
            return CodeUtils.Message.builder().code(55044).message("服务器发送错误").build();
        }
    }

//        弃用 服务器无法使用腾讯云防水墙
    @Deprecated
    @GetMapping(value = "/authentication/verify")
    public CodeUtils.Message verify(@RequestParam String ticket, @RequestParam String randInt, HttpServletRequest request){
            String host  = request.getRemoteHost();
            int result = VerifyService.verifyTicket(ticket,randInt,host);
        System.out.println(result);
            if (result!=-1)
            {
                return CodeUtils.Message.builder().code(20000).message(Integer.toString(result)).build();
            }
            return CodeUtils.Message.builder().message("验证信息有误").code(44033).build();
    }


    // 注册
    @RequestMapping(value = "/authentication/register", method = RequestMethod.POST)
    public CodeUtils.Message register(@RequestBody Person addedUser , @Nullable @RequestParam Integer invitecode ) throws AuthenticationException, JsonProcessingException {
        try {
            final String username = addedUser.getUsername();
            if( personRepository.findByUsername(username)!=null ) {
                return CodeUtils.Message.builder().code(55044).message("该用户名已存在").build();
            }
            if (addedUser.getOpenId()!=null&&personRepository.findByOpenId(addedUser.getOpenId())!=null){
                return CodeUtils.Message.builder().code(55044).message("该微信账号已存在").build();
            }
            if (invitecode!=null)
            {
                if (!invitecode.equals(IntelligenceCommunitySystemApplication.inviteCode))
                {
                    return CodeUtils.Message.builder().code(CodeUtils.AUTH_ERROR).message("输入的邀请码有误或超时").build();
                }
                addedUser = authService.registerWorker(addedUser);
            }else {
                addedUser = authService.registerUser(addedUser);
            }
            return CodeUtils.Message.builder().code(20000).message(new ObjectMapper().writeValueAsString(addedUser)).build();
        }catch (JsonProcessingException e){
            e.printStackTrace();
            return CodeUtils.Message.builder().code(CodeUtils.SERVER_ERROR).message("后端读写错误").build();
        }
    }

    @Transactional
    @GetMapping("/authentication/associate")
    public CodeUtils.Message associate(@RequestParam String username, @RequestParam String openId){
        try{
            personRepository.associateOpenIdWithUserName(openId,username,new Date());
            return CodeUtils.Message.builder().message("关联成功").code(20000).build();
        }catch (Exception e){
            e.printStackTrace();
            return CodeUtils.Message.builder().message("参数有误").code(44033).build();
        }
    }
//      用户 扫码登录 （uuid）==》 websocket sendMessage
    @GetMapping("/authentication/qcode")
   public CodeUtils.Message sendUUIDAndTokenToWebSocket(@RequestParam String uuid,HttpServletRequest request) throws IOException {
        try {
            String token = request.getHeader(ConstUtils.TokenUtils.TOKEN_HEADERS);
            QrcodeWebsocket.sendMessage(uuid,token);
            return CodeUtils.Message.builder().message("认证成功").code(20000).build();
        }catch (Exception e){
            return CodeUtils.Message.builder().message("参数有误").code(44033).build();
        }
   }
}
